package cn.edu.ncu.housinghub.service.impl;

import cn.edu.ncu.housinghub.dto.request.user.ChangePasswordRequest;
import cn.edu.ncu.housinghub.dto.request.user.RegisterRequest;
import cn.edu.ncu.housinghub.dto.request.user.UserProfileRequest;
import cn.edu.ncu.housinghub.dto.response.user.UserProfileResponse;
import cn.edu.ncu.housinghub.entity.user.Agent;
import cn.edu.ncu.housinghub.entity.user.IdentityInfo;
import cn.edu.ncu.housinghub.entity.user.Landlord;
import cn.edu.ncu.housinghub.entity.user.User;
import cn.edu.ncu.housinghub.exception.BusinessException;
import cn.edu.ncu.housinghub.constant.ErrorCodeConstant;
import cn.edu.ncu.housinghub.constant.SystemConstant;
import cn.edu.ncu.housinghub.mapper.UserMapper;
import cn.edu.ncu.housinghub.service.UserService;
import cn.edu.ncu.housinghub.utils.common.TokenUtil;
import cn.edu.ncu.housinghub.utils.security.PasswordEncoder;
import cn.edu.ncu.housinghub.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 实现（注册、登录逻辑）
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public User authenticate(String email, String password) {
        try {
            // 查询数据库验证用户邮箱和密码
            User user = userMapper.selectByEmail(email);

            // 验证密码
            if (user != null && PasswordEncoder.matches(password, user.getPassword())) {
                return user;
            }
            return null;
        } catch (Exception e) {
            throw new BusinessException(ErrorCodeConstant.USER_AUTH_ERROR, e);
        }
    }

    @Override
    public User findByEmail(String email) {
        try {
            // 查询数据库查找用户
            return userMapper.selectByEmail(email);
        } catch (Exception e) {
            throw new BusinessException(ErrorCodeConstant.USER_QUERY_ERROR, e);
        }
    }

    @Override
    public User save(RegisterRequest registerRequest) {

        try {
            // 创建新用户
            User user = new User();
            user.setUsername(registerRequest.getUsername());
            user.setEmail(registerRequest.getEmail());
            user.setPassword(registerRequest.getPassword());
            user.setRole(SystemConstant.ROLE_TENANT.getIntegerValue()); // 默认为租客
            // 设置创建时间
            user.setCreateTime(LocalDateTime.now());

            // 设置默认性别为男
            user.setGender("男");

            // 设置默认头像（根据性别）
            user.setAvatar("https://housinghub-system.oss-cn-hangzhou.aliyuncs.com/avatars/default-male.png");

            // 设置默认角色为租客
            if (user.getRole() == null) {
                user.setRole(SystemConstant.ROLE_TENANT.getIntegerValue());
            }

            // 对密码进行加密
            user.setPassword(PasswordEncoder.encode(user.getPassword()));

            // 保存用户到数据库
            int result = userMapper.insertUser(user);
            if (result <= 0) {
                throw new BusinessException(ErrorCodeConstant.USER_SAVE_ERROR, ErrorCodeConstant.USER_SAVE_ERROR.getMessage());
            }
            return user;
        } catch (BusinessException e) {
            throw e; // 重新抛出业务异常
        } catch (Exception e) {
            throw new BusinessException(ErrorCodeConstant.USER_SAVE_ERROR, e);
        }
    }

    @Override
    public void logout(String info) {
        if (info==null)
            return;
        String theKey = SystemConstant.REDIS_TOKEN_PREFIX_USER.getStringValue() + "*:" + info;
        Set keys = redisTemplate.keys(theKey);
        if (keys.size()>0) {
            Object key = keys.iterator().next();
            redisTemplate.delete(key);
        }
    }

    /**
     * 清理所有用户的Redis缓存
     */
    public void clearAllUserCache() {
        try {
            String pattern = SystemConstant.REDIS_TOKEN_PREFIX_USER.getStringValue() + "*";
            Set<String> keys = redisTemplate.keys(pattern);
            if (!keys.isEmpty()) {
                redisTemplate.delete(keys);
                System.out.println("已清理 " + keys.size() + " 个用户缓存");
            }
        } catch (Exception e) {
            System.err.println("清理用户缓存失败: " + e.getMessage());
        }
    }

    @Override
    public Result getToken(User user) {
        // 从redis中查看用户是否已经登录
        Set<String> keys = redisTemplate.keys(
                SystemConstant.REDIS_TOKEN_PREFIX_USER.getStringValue() + user.getId().toString() + ":*");
        if (!keys.isEmpty()) {
            // 如果用户已经登录 则将已登录的用户删除
            redisTemplate.delete(keys.iterator().next());
            System.out.println("🔄 删除了用户的旧token，用户ID: " + user.getId());
        }

        // 生成新token
        String token = UUID.randomUUID().toString();
        // 将用户信息存储到Redis中
        redisTemplate.opsForValue().set(
                SystemConstant.REDIS_TOKEN_PREFIX_USER.getStringValue() +
                        user.getId().toString() + ":" + token,
                user,
                SystemConstant.REDIS_TOKEN_EXPIRE_TIME.getIntegerValue(),
                TimeUnit.MINUTES
        );
        System.out.println("✅ 用户新token已存储，用户ID: " + user.getId() + ", token: " + token.substring(0, 8) + "...");
        ConcurrentHashMap<String, Object> loginMap = new ConcurrentHashMap<>();
        loginMap.put("info", token);
        loginMap.put("loginUser", user);
        // 返回token给前端
        return Result.success(loginMap);
    }

    @Transactional
    @Override
    public Result verifyIdentity(User user, String realName, String identityCard) {
        try {
            // 检查用户是否已经实名认证
            if (user.getIsIdentityVerified()) {
                throw new BusinessException(ErrorCodeConstant.USER_ALREADY_VERIFIED);
            }

            // 创建实名认证信息
            IdentityInfo identityInfo = new IdentityInfo(user.getId(), realName, identityCard);

            // 更新用户的实名认证状态
            user.setIsIdentityVerified(true);

            // 保存实名认证信息到数据库
            userMapper.insertIdentityInfo(identityInfo);
            userMapper.updateIdentityVerified(user);

            // 返回成功结果
            return Result.success("实名认证成功");
        } catch (Exception e) {
            throw new BusinessException(ErrorCodeConstant.IDENTITY_VERIFICATION_ERROR, e);
        }
    }

    @Override
    public User getUserByToken(String token) {
        try {
            // 从Redis中获取用户信息
            String keyPattern = SystemConstant.REDIS_TOKEN_PREFIX_USER.getStringValue() + "*:" + token;
            Set<String> keys = redisTemplate.keys(keyPattern);
            if (keys.isEmpty()) {
                return null;
            }

            return (User) redisTemplate.opsForValue().get(keys.iterator().next());
        } catch (Exception e) {
            throw new BusinessException(ErrorCodeConstant.REDIS_ERROR, e);
        }
    }

    @Override
    public User findById(Long id) {
        return userMapper.selectById(id);
    }

    @Override
    public void modifyUserRoleToLandlord(Long userId) {
        userMapper.updateRoleToLandlord(userId);
    }

    @Override
    public void addNewLandlord(Landlord landlord) {
        userMapper.insertNewLandlord(landlord);
    }

    @Override
    public Landlord findLandlordByUserId(Long userId) {
        return userMapper.selectLandlordByUserId(userId);
    }

    @Override
    public void modifyUserRoleToAgent(Long userId) {
        userMapper.updateRoleToAgent(userId);
    }

    @Override
    public void addNewAgent(Agent agent) {
        userMapper.addNewAgent(agent);
    }

    @Override
    public Agent findAgentByUserID(Long userId) {
        return userMapper.selectAgentByUserId(userId);
    }

    @Override
    public UserProfileResponse getUserProfile(String token) {
        try {
            // 通过token获取用户信息
            User user = TokenUtil.getUserByToken(token);
            if (user == null) {
                throw new BusinessException(ErrorCodeConstant.INVALID_TOKEN);
            }

            // 如果用户已实名认证，查询实名认证信息
            IdentityInfo identityInfo = null;
            if (user.getIsIdentityVerified()) {
                identityInfo = userMapper.selectIdentityInfoByUserId(user.getId());
            }

            // 返回用户个人资料响应
            return new UserProfileResponse(user, identityInfo);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            throw new BusinessException(ErrorCodeConstant.USER_QUERY_ERROR, e);
        }
    }

    @Override
    public Result updateUserProfile(String token, UserProfileRequest profileRequest) {
        try {
            // 通过token获取用户信息
            User user = TokenUtil.getUserByToken(token);
            if (user == null) {
                throw new BusinessException(ErrorCodeConstant.INVALID_TOKEN);
            }

            // 更新用户信息
            user.setUsername(profileRequest.getUsername());
            user.setPhone(profileRequest.getPhone());

            // 处理性别和头像
            String oldGender = user.getGender();
            String newGender = profileRequest.getGender();

            // 转换性别字符串为数据库兼容格式
            Integer genderCode = convertGenderToCode(newGender);
            user.setGender(String.valueOf(genderCode));

            // 如果性别改变且用户使用的是默认头像，则更新为对应性别的默认头像
            String currentAvatar = user.getAvatar();
            boolean isDefaultAvatar = currentAvatar != null &&
                (currentAvatar.contains("default-male.png") || currentAvatar.contains("default-female.png"));

            if (isDefaultAvatar && !newGender.equals(oldGender)) {
                // 性别改变且使用默认头像，更新为新性别的默认头像
                String newDefaultAvatar = "女".equals(newGender)
                    ? "https://housinghub-system.oss-cn-hangzhou.aliyuncs.com/avatars/default-female.png"
                    : "https://housinghub-system.oss-cn-hangzhou.aliyuncs.com/avatars/default-male.png";
                user.setAvatar(newDefaultAvatar);
            } else if (profileRequest.getAvatar() != null && !profileRequest.getAvatar().isEmpty()) {
                // 用户上传了新头像
                user.setAvatar(profileRequest.getAvatar());
            }

            user.setBirthday(profileRequest.getBirthday());
            user.setCity(profileRequest.getCity());
            user.setBio(profileRequest.getBio());

            // 更新数据库
            userMapper.updateUserProfile(user);

            // 同步更新Redis中的用户信息
            updateUserInRedis(token, user);

            return Result.success("个人资料更新成功");
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            throw new BusinessException(ErrorCodeConstant.USER_UPDATE_ERROR, e);
        }
    }

    /**
     * 更新Redis中的用户信息
     * @param token 用户token
     * @param user 更新后的用户信息
     */
    private void updateUserInRedis(String token, User user) {
        try {
            // 查找Redis中的用户信息key
            String keyPattern = SystemConstant.REDIS_TOKEN_PREFIX_USER.getStringValue() + "*:" + token;
            Set<String> keys = redisTemplate.keys(keyPattern);

            if (!keys.isEmpty()) {
                String key = keys.iterator().next();
                // 更新Redis中的用户信息
                redisTemplate.opsForValue().set(key, user);
            }
        } catch (Exception e) {
            // 记录日志但不抛出异常，避免影响主要业务流程
            System.err.println("更新Redis用户信息失败: " + e.getMessage());
        }
    }

    @Override
    public Result changePassword(String token, ChangePasswordRequest changePasswordRequest) {
        try {
            // 验证新密码和确认密码是否一致
            if (!changePasswordRequest.isPasswordMatch()) {
                throw new BusinessException(ErrorCodeConstant.PASSWORD_MISMATCH);
            }

            // 通过token获取用户信息
            User user = TokenUtil.getUserByToken(token);
            if (user == null) {
                throw new BusinessException(ErrorCodeConstant.INVALID_TOKEN);
            }

            // 验证原密码
            if (!PasswordEncoder.matches(changePasswordRequest.getOldPassword(), user.getPassword())) {
                throw new BusinessException(ErrorCodeConstant.INVALID_OLD_PASSWORD);
            }

            // 加密新密码
            String encodedNewPassword = PasswordEncoder.encode(changePasswordRequest.getNewPassword());
            user.setPassword(encodedNewPassword);

            // 更新数据库
            userMapper.updatePassword(user);

            return Result.success("密码修改成功");
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            throw new BusinessException(ErrorCodeConstant.PASSWORD_CHANGE_ERROR, e);
        }
    }

    /**
     * 转换性别字符串为数据库兼容格式
     * @param gender 性别字符串
     * @return 性别代码
     */
    private Integer convertGenderToCode(String gender) {
        if (gender == null) {
            return 0; // 未知
        }

        switch (gender.toLowerCase()) {
            case "男":
            case "male":
            case "1":
                return 1;
            case "女":
            case "female":
            case "2":
                return 2;
            default:
                return 0; // 未知
        }
    }
}
